<?php

namespace controller\admin;

defined('IA_ROOT') || exit();

use mvc\Controller;
use facade\Model;
use facade\View;
use facade\Util;

class Account extends Controller
{
    // 基址
    protected $site_url;
    protected $subdir;

    // smtp邮件
    private $smtp;

    // 初始化
    protected function initialize()
    {
        !session_id() && session_start();
        $this->site_url = Util::url();
        $this->subdir = Util::subdir();
        $this->smtp = [
            'email' => '',
            'code' => '', // 授权码
            'service' => ''
        ];
        $setting = Model::fetch('SELECT * FROM `setting` WHERE id=:id ORDER BY `id` ASC LIMIT 1', [':id' => 1]);
        if ($setting && ($check = json_decode($setting['value'], true)) && !empty($check['email']) && !empty($check['code']) && !empty($check['service'])) {
            $this->smtp = [
                'email' => $check['email'],
                'code' => $check['code'], // 授权码
                'service' => $check['service']
            ];
        }
        View::assign('site_url', $this->site_url);
    }

    // 登录
    public function index()
    {
        $param = Util::param(['redirect_to']);
        $jump = isset($param['redirect_to']) && false === strpos($param['redirect_to'], '/login') ? htmlentities($param['redirect_to']) : Util::url('/admin/');
        if ($this->checkLogin())
            exit(Util::errMsg(['code' => 0, 'msg' => '你已经登录', 'url' => $jump]));
        if (Util::isAjax()) {
            $ip = Util::getIp();
            $param = Util::param(['username', 'password', 'captcha', 'remember']);
            empty($param['username']) && Util::errMsg('请输入用户名或邮箱');
            $check_type = false === strpos($param['username'], '@') ? 'username' : 'email';
            if (($check_type == 'username' && !preg_match('#^[a-z0-9_-]{3,12}$#', $param['username'])) || ($check_type == 'email' && !filter_var($param['username'], FILTER_VALIDATE_EMAIL)))
                Util::errMsg('用户名或邮箱格式错误, 用户名3~12位只能字母数字下划线或中划线');
            if (empty($param['password']) || strlen($param['password']) < 5)
                Util::errMsg('密码至少5位');
            if (empty($param['captcha']) || strtolower($param['captcha']) !== strtolower($_SESSION['captcha']))
                Util::errMsg('验证码不正确');
            if (!in_array($param['remember'], [0, 1]))
                Util::errMsg('包含非法参数');

            // 数据库查询
            $user = Model::fetch("SELECT * FROM `user` WHERE `$check_type`=:username AND `password`=:password ORDER BY `id` ASC LIMIT 1", [
                'username' => $param['username'],
                'password' => md5(base64_encode($param['password']))
            ]);
            if (!$user) {
                Util::config('log') && Model::insert('log', ['author' => $param['username'], 'request_method' => 'ajax', 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '管理登录', 'message' => "用户名或密码错误", 'ip' => $ip, 'status' => 1, 'time' => time()]);
                Util::errMsg('用户名或密码错误');
            }
            if ('1' == $user['status']) {
                Util::config('log') && Model::insert('log', ['author' => $param['username'], 'request_method' => 'ajax', 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '管理登录', 'message' => "账号被禁用", 'ip' => $ip, 'status' => 1, 'time' => time()]);
                Util::errMsg('你的账号已被禁用，请联系管理员');
            }

            // 登录成功
            $_SESSION['uid'] = $user['id'];

            // 记住登录
            $token = md5($user['username'] . md5(base64_encode($user['password'])));
            if ('1' == $param['remember']) {
                setcookie('token', $token, time() + 3600 * 24 * 30, '/');
                Model::update('user', ['remember_token' => $token], ['id' => $user['id']]);
            } else {
                Model::update('user', ['remember_token' => ''], ['id' => $user['id']]);
            }

            // 单点登录
            $setting = Model::fetch('SELECT * FROM `setting` WHERE id=:id ORDER BY `id` ASC LIMIT 1', [':id' => 1]);
            if ($setting && ($check = json_decode($setting['value'], true)) && isset($check['alone_login']) && $check['alone_login']) {
                $randstr = md5($token . rand(100000, 999999));
                Util::setCache('rand' . $user['id'], $randstr);
                setcookie('randstr', $randstr, time() + 3600 * 24 * 30, '/');
            }

            // 更新时间
            !$user['first_login'] && Model::update('user', ['first_login' => time()], ['id' => $user['id']]);
            Model::update('user', ['last_login' => time()], ['id' => $user['id']]);

            // 记录日志
            Util::config('log') && Model::insert('log', ['author' => $user['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '管理登录', 'message' => '登录成功', 'ip' => $ip, 'status' => 0, 'time' => time()]);

            // 清除来源页缓存
            $this->clearOrgin();

            // 登录跳转
            exit(Util::errMsg(['code' => 0, 'msg' => '登录成功', 'token' => $token, 'url' => $jump]));
        }
        View::display('admin/account/login.html');
    }

    // 登出
    public function logout()
    {
        $param = Util::param(['redirect_to']);
        $jump = isset($param['redirect_to']) && false === strpos($param['redirect_to'], '/logout') ? htmlentities($param['redirect_to']) : Util::url('/admin/login.html');
        $row = $this->checkLogin();
        !$row && exit(Util::errMsg(['code' => 0, 'msg' => '你已登出', 'url' => $jump]));;
        // 清除token
        Model::update('user', ['remember_token' => ''], ['id' => $row['id']]);
        // 记录日志
        $username = Model::fetchColumn("SELECT `username` FROM `user` WHERE `id`=:id ORDER BY `id` ASC LIMIT 1", ['id' => $row['id']]);
        Util::config('log') && Model::insert('log', ['author' => $username, 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '管理登录', 'message' => '登出成功', 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
        // 清除session和cookie
        unset($_SESSION['uid']);
        setcookie('token', '', time() - 3600, '/');
        setcookie('randstr', '', time() - 3600, '/');
        Util::delCache('rand' . $row['id']);
        // 清除来源页缓存
        $this->clearOrgin();
        exit(Util::errMsg(['code' => 0, 'msg' => '登出成功', 'token' => '', 'url' => $jump]));
    }

    // 注册
    public function register()
    {
        $param = Util::param(['redirect_to']);
        $jump = isset($param['redirect_to']) && false === strpos($param['redirect_to'], '/register') ? htmlentities($param['redirect_to']) : Util::url('/admin/');
        if ($this->checkLogin())
            exit(Util::errMsg(['code' => 0, 'msg' => '你已经登录', 'url' => $jump]));
        if (Util::isAjax()) {
            $param = Util::param(['username', 'password', 'repeat_password', 'captcha', 'email', 'nickname', 'phone', 'remember']);
            if (empty($param['username']) || !preg_match('#^[a-z0-9_-]{3,12}$#', $param['username']))
                Util::errMsg('用户名3~12位只能字母数字下划线或中划线');
            $check = Model::fetchColumn("SELECT `username` FROM `user` WHERE `username`=:username ORDER BY `id`", [':username' => $param['username']]);
            $check && Util::errMsg('用户名已存在');
            if (empty($param['password']) || strlen($param['password']) < 5)
                Util::errMsg('密码至少5位');
            if ($param['password'] !== $param['repeat_password'])
                Util::errMsg('两次密码输入不一致');
            if (!isset($param['email']) || (!empty($param['email']) && !filter_var($param['email'], FILTER_VALIDATE_EMAIL)))
                Util::errMsg('邮箱格式错误');
            if (!empty($param['email'])) {
                $check = Model::fetchColumn("SELECT `email` FROM `user` WHERE `email`=:email ORDER BY `id`", [':email' => $param['email']]);
                $check && Util::errMsg('邮箱已存在');
            }
            if (empty($param['captcha']) || strtolower($param['captcha']) !== strtolower($_SESSION['captcha']))
                Util::errMsg('验证码不正确');
            if (!empty($param['nickname']) && !preg_match('#^[\x{4e00}-\x{9fa5}A-Za-z0-9_-]{2,12}$#u', $param['nickname']))
                Util::errMsg('昵称2~12位只能中英文字母数字下划线中划线');
            if (!empty($param['phone']) && !preg_match('#^1((34[0-8]\d{7})|((3[0-3|5-9])|(4[5-7|9])|(5[0-3|5-9])|(66)|(7[2-3|5-8])|(8[0-9])|(9[1|8|9]))\d{8})$#', $param['phone']))
                Util::errMsg('手机号码不正确');

            $remember_me = $param['remember'];
            $param['password'] = md5(base64_encode($param['password']));
            unset($param['repeat_password']);
            unset($param['captcha']);
            unset($param['remember']);

            // 验证手机号重复
            if (!empty($param['phone'])) {
                $check = Model::fetchColumn("SELECT `phone` FROM `user` WHERE `phone`=:phone ORDER BY `id`", [':phone' => $param['phone']]);
                $check && Util::errMsg('手机号码已存在');
            }

            // 写入数据库记录日志
            $param['role_id'] = 2;
            $param['reg_time'] = time();
            $lastInsertId = Model::insert('user', $param);
            if ($lastInsertId) {
                // 注册后登录
                $_SESSION['uid'] = $lastInsertId;

                // 记住登录
                $token = md5($param['username'] . md5(base64_encode($param['password'])));
                if ('1' == $remember_me) {
                    setcookie('token', $token, time() + 3600 * 24 * 30, '/');
                    Model::update('user', ['remember_token' => $token], ['id' => $lastInsertId]);
                } else {
                    Model::update('user', ['remember_token' => ''], ['id' => $lastInsertId]);
                }

                // 单点登录
                $setting = Model::fetch('SELECT * FROM `setting` WHERE id=:id ORDER BY `id` ASC LIMIT 1', [':id' => 1]);
                if ($setting && ($check = json_decode($setting['value'], true)) && isset($check['alone_login']) && $check['alone_login']) {
                    $randstr = md5($token . rand(100000, 999999));
                    Util::setCache('rand' . $lastInsertId, $randstr);
                    setcookie('randstr', $randstr, time() + 3600 * 24 * 30, '/');
                }

                // 更新时间
                $user = Model::fetch('SELECT * FROM `user` WHERE `id`=:id', [':id' => $lastInsertId]);
                !$user['first_login'] && Model::update('user', ['first_login' => time()], ['id' => $user['id']]);
                Model::update('user', ['last_login' => time()], ['id' => $user['id']]);

                // 清除来源页缓存
                $this->clearOrgin();
                Util::config('log') && Model::insert('log', ['author' => $param['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '用户注册', 'message' => "用户注册 {$param['username']} 成功", 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
                Util::errMsg(['code' => 0, 'msg' => '注册成功', 'token' => $token, 'url' => $jump]);
            } else {
                Util::config('log') && Model::insert('log', ['author' => $param['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '用户注册', 'message' => "用户注册 {$param['username']} 失败", 'ip' => Util::getIp(), 'status' => 1, 'time' => time()]);
                Util::errMsg(['code' => 1, 'msg' => '注册失败']);
            }
            return;
        }
        View::display('admin/account/register.html');
    }

    // 忘记密码
    public function forget()
    {
        $param = Util::param(['redirect_to']);
        $jump = isset($param['redirect_to']) && false === strpos($param['redirect_to'], '/forget') ? htmlentities($param['redirect_to']) : Util::url('/admin/');
        if ($this->checkLogin())
            exit(Util::errMsg(['code' => 0, 'msg' => '你已经登录', 'url' => $jump]));
        if (Util::isAjax()) {
            $param = Util::param(['email', 'captcha', 'password', 'repeat_password', 'verify']);
            empty($param['email']) && Util::errMsg('请输入邮箱地址');
            !filter_var($param['email'], FILTER_VALIDATE_EMAIL) && Util::errMsg('邮箱格式错误');
            $user = Model::fetch("SELECT * FROM `user` WHERE `email`=:email", [':email' => $param['email']]);
            !$user && Util::errMsg('邮箱不存在或未注册');
            empty($param['verify']) || !in_array($param['verify'], ['send', 'reset']) && Util::errMsg('字段错误');
            if (!session_id()) session_start();

            // 发送验证码
            if ($param['verify'] == 'send') {
                $verycode = mt_rand(100000, 999999);
                $_SESSION['email_verycode'] = [
                    'code' => $verycode,
                    'email' => $param['email'],
                    'expire' => time() + 600 // 10分钟有效期
                ];
                (empty($this->smtp['email']) || empty($this->smtp['code']) || empty($this->smtp['service'])) && Util::errMsg('SMTP 配置错误');
                $sendmail = Util::sendMail($param['email'], '您的验证码', '您的验证码: ' . $verycode . ' 验证码 10 分钟内有效', $this->smtp['email'], $this->smtp['code'], $this->smtp['service']);
                if ($sendmail === true) return Util::errMsg(['code' => 0, 'msg' => '验证邮件已发送至 ' . $param['email']]);
                Util::errMsg(['code' => 1, 'msg' => $sendmail]);
            }

            // 重置密码
            if ($param['verify'] == 'reset') {
                if (!isset($_SESSION['email_verycode']) || !isset($_SESSION['email_verycode']['code']) || !isset($_SESSION['email_verycode']['email']) || empty($param['captcha']) || $_SESSION['email_verycode']['code'] != $param['captcha'] || empty($_SESSION['email_verycode']['expire']) || $_SESSION['email_verycode']['expire'] < time())
                    Util::errMsg('验证码错误或已过期');
                if (empty($param['password']) || strlen($param['password']) < 5)
                    Util::errMsg('密码至少5位');
                if ($param['password'] !== $param['repeat_password'])
                    Util::errMsg('两次密码输入不一致');
                unset($_SESSION['email_verycode']);

                // 写入数据库记录日志
                $rowCount = Model::update('user', ['password' => md5(base64_encode($param['password'])), 'remember_token' => ''], ['email' => $param['email']]);
                if ($rowCount) {
                    Util::config('log') && Model::insert('log', ['author' => $user['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '重置密码', 'message' => "重置密码 {$user['username']} ({$user['email']}) 成功", 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
                    Util::errMsg(['code' => 0, 'msg' => '密码重置成功, 请重新登录']);
                } else {
                    Util::config('log') && Model::insert('log', ['author' => $user['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '重置密码', 'message' => "没有改变 {$user['username']} ({$user['email']}) 信息", 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
                    Util::errMsg(['code' => 1, 'msg' => '没有改变信息']);
                }
            }
            return;
        }
        View::display('admin/account/forget.html');
    }

    // 修改资料
    public function profile()
    {
        $row = $this->checkLogin();
        !$row && Util::errMsg(['msg' => '请先登录', 'url' => Util::url('/admin/login.html')]);
        if (!empty($row['avatar']) && preg_match('#(/static/upload/[^\.]+\.(gif|jpe?g|png|webp|svg))#i', $row['avatar'], $match)) {
            $row['avatar'] = $this->subdir . $match[1];
        }
        if (Util::isAjax()) {
            $param = Util::param(['id', 'username', 'password', 'nickname', 'phone', 'avatar']);
            $user = Model::fetch("SELECT * FROM `user` WHERE `id`=:id", [':id' => $param['id']]);
            (!$user || $param['id'] != $row['id']) && Util::errMsg('ID错误');
            if (!empty($param['password'])) {
                strlen($param['password']) < 5 && Util::errMsg('密码至少5位');
                $param['username'] == 'anonymous' && Util::errMsg('该用户密码不可修改');
                $param['password'] = md5(base64_encode($param['password']));
            } else {
                unset($param['password']);
            }
            if (!empty($param['nickname']) && !preg_match('#^[\x{4e00}-\x{9fa5}A-Za-z0-9_-]{2,12}$#u', $param['nickname']))
                Util::errMsg('昵称2~12位只能中英文字母数字下划线中划线');
            if (!empty($param['phone']) && !preg_match('#^1((34[0-8]\d{7})|((3[0-3|5-9])|(4[5-7|9])|(5[0-3|5-9])|(66)|(7[2-3|5-8])|(8[0-9])|(9[1|8|9]))\d{8})$#', $param['phone']))
                Util::errMsg('手机号码不正确');
            if (!empty($param['avatar'])) {
                !preg_match('/\.(gif|jpe?g|png|webp|svg)$/i', $param['avatar']) && Util::errMsg('图片格式错误');
                if (preg_match('#(/static/upload/[^\.]+\.(gif|jpe?g|png|webp|svg))#i', $param['avatar'], $match)) {
                    $param['avatar'] = $match[1];
                }
            }

            // 更新数据库记录日志
            $rowCount = Model::update('user', $param, ['id' => $param['id']]);
            // 修改媒体状态
            $paths = [0 => [], 1 => [], 2 => []];
            if (!empty($user['avatar']) && preg_match('#(/static/upload/[^\.]+\.(gif|jpe?g|png|webp|svg))#i', $user['avatar'], $match)) {
                if (is_file(IA_ROOT . $match[1])) {
                    $paths[1][] = $match[1];
                } else {
                    $paths[2][] = $match[1];
                }
            }
            if (!empty($param['avatar']) && preg_match('#(/static/upload/[^\.]+\.(gif|jpe?g|png|webp|svg))#i', $param['avatar'], $match)) {
                if (is_file(IA_ROOT . $match[1])) {
                    $paths[0][] = $match[1];
                } else {
                    $paths[2][] = $match[1];
                }
            }
            $paths[1] = array_filter($paths[1], function ($item) use ($paths) {
                return !in_array($item, $paths[0]);
            });
            $paths[1] && Model::update('media', ['status' => 1], ['path' => array_unique($paths[1])]);
            $paths[0] && Model::update('media', ['status' => 0], ['path' => array_unique($paths[0])]);
            $paths[2] && Model::update('media', ['status' => 2], ['path' => array_unique($paths[2])]);
            if ($rowCount) {
                Util::config('log') && Model::insert('log', ['author' => $user['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '修改资料', 'message' => "修改资料 {$user['username']} 成功", 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
                Util::errMsg(['code' => 0, 'msg' => '修改资料成功']);
            } else {
                Util::config('log') && Model::insert('log', ['author' => $user['username'], 'request_method' => Util::requestMethod(), 'url' => htmlentities($_SERVER['REQUEST_URI']), 'title' => '修改资料', 'message' => "没有改变 {$user['username']} 信息", 'ip' => Util::getIp(), 'status' => 0, 'time' => time()]);
                Util::errMsg(['code' => 1, 'msg' => '没有改变信息']);
            }
            return;
        }
        View::assign('row', $row);
        View::display('admin/account/profile.html');
    }

    // 邮件联系
    public function sendmail()
    {
        $row = $this->checkLogin();
        !$row && Util::errMsg(['msg' => '请先登录', 'url' => Util::url('/admin/login.html')]);
        if (Util::isAjax()) {
            $param = Util::param(['id', 'nickname', 'from', 'to', 'title', 'content', 'send_type']);
            $user = Model::fetch("SELECT * FROM `user` WHERE `id`=:id", [':id' => isset($param['id']) ? $param['id'] : 0]);
            (!$user || $param['id'] != $row['id']) && Util::errMsg('ID ' . '错误');
            empty($param['from']) && Util::errMsg('请输入发件人邮箱');
            !filter_var($param['from'], FILTER_VALIDATE_EMAIL) && Util::errMsg('发件人邮箱格式错误');
            empty($param['to']) && Util::errMsg('请输入收件邮箱');
            !filter_var($param['from'], FILTER_VALIDATE_EMAIL) && Util::errMsg('收件人邮箱格式错误');
            if (isset($param['send_type']) && $param['send_type'] == 'test') {
                $param['from'] !== $this->smtp['email'] && Util::errMsg('发件人邮箱不可更改');
                (empty($this->smtp['email']) || empty($this->smtp['code']) || empty($this->smtp['service'])) && Util::errMsg('SMTP 配置错误');
            } else {
                $param['to'] !== 'hallelujahlord@foxmail.com' && Util::errMsg('收件人邮箱不可更改');
            }
            empty($param['title']) && Util::errMsg('请输入邮件标题');
            empty($param['content']) && Util::errMsg('请输入邮件内容');
            $sendmail = Util::sendMail($param['to'], (isset($param['send_type']) && $param['send_type'] == 'test' ? '' : ($row['nickname'] ?: $row['username']) . '-') . $param['title'], (isset($param['send_type']) && $param['send_type'] == 'test' ? '' : '<p>' . $row['username'] . ' (' . $param['from'] . ') ' . $row['nickname'] . '</p>') . $param['content'], (isset($param['send_type']) && $param['send_type'] == 'test' ? $param['from'] : $param['to']), (isset($param['send_type']) && $param['send_type'] == 'test' ? $this->smtp['code'] : 'tfhfguwzazjhbcad'), (isset($param['send_type']) && $param['send_type'] == 'test' ? $this->smtp['service'] : 'qq'));
            if ($sendmail === true) return Util::errMsg(['code' => 0, 'msg' => '邮件发送成功，等待查收!']);
            Util::errMsg(['code' => 2, 'msg' => $sendmail]);
        }
        View::assign('row', $row);
        View::assign('smtp_email', $this->smtp['email']);
        View::display('admin/account/sendmail.html');
    }

    // 图片验证码
    public function captcha()
    {
        Util::captcha();
    }

    // 清除缓存
    public function clear()
    {
        foreach (glob(IA_ROOT . '/mvc/tpl/*/*.php') as $file)
            @unlink($file);
        foreach (glob(IA_ROOT . '/mvc/tpl/*') as $dir)
            @rmdir($dir);
        exit(Util::errMsg(['code' => 0, 'msg' => '清除成功']));
    }

    // 清除来源页缓存
    private function clearOrgin()
    {
        if (isset($_SERVER["HTTP_REFERER"])) {
            $file_name = md5($_SERVER["HTTP_REFERER"]);
            if ($pos = strpos($_SERVER["HTTP_REFERER"], 'redirect_to=')) {
                $file_name = md5(substr($_SERVER["HTTP_REFERER"], $pos + 12));
            }
            $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
            is_file($cache_file) && unlink($cache_file);
        }
    }

    // 检查登录
    private function checkLogin()
    {
        $row = false;
        if (!isset($_SESSION['uid']) || empty($_SESSION['uid'])) {
            if (!isset($_COOKIE['token']) || empty($_COOKIE['token'])) return false;
            $row = Model::fetch("SELECT * FROM `user` WHERE `remember_token`=:token ORDER BY `id` ASC LIMIT 1", [':token' => $_COOKIE['token']]);
            if (!$row) return false;
            $_SESSION['uid'] = $row['id'];
        }
        !$row && $row = Model::fetch("SELECT * FROM `user` WHERE `id`=:id ORDER BY `id` ASC LIMIT 1", [':id' => $_SESSION['uid']]);
        if (!$row) return false;

        // 检查单点登录
        $setting = Model::fetch('SELECT * FROM `setting` WHERE id=:id ORDER BY `id` ASC LIMIT 1', [':id' => 1]);
        if ($setting && ($check = json_decode($setting['value'], true)) && isset($check['alone_login']) && $check['alone_login']) {
            $randstr = isset($_COOKIE['randstr']) ? $_COOKIE('randstr') : false;
            $cache_randstr = Util::getCache('rand' . $row['id']);
            if ($randstr !== $cache_randstr) {
                return false;
            }
        }

        return $row;
    }
}
